
package com.ccloud.common.im.config;

import com.ccloud.common.core.utils.StringUtils;
import com.ccloud.common.im.constant.CIMConstant;
import com.ccloud.common.im.constant.properties.CIMProperties;
import com.ccloud.common.im.enums.SocketHandlerEnum;
import com.ccloud.common.im.handler.AuthorizationHandler;
import com.ccloud.common.im.handler.CIMRequestHandler;
import com.ccloud.common.im.handler.SessionClosedHandler;
import com.ccloud.common.im.model.CIMMsg;
import com.ccloud.common.im.model.CIMSession;
import com.ccloud.common.im.server.CIMNioSocketServer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author chentl
 * @Version V1.0
 * @Project wh-bigdata-frame.
 * @Title CIMConfig
 * @Description CIM 启动配置类
 * @Package com.bigdata.im.server.config
 * @Date 2021/6/18 3:30 下午
 */
@Slf4j
@Configuration
public class CIMConfig implements CIMRequestHandler, ApplicationListener<ApplicationStartedEvent> {

    @Resource
    private ApplicationContext applicationContext;

    @Resource
    private CIMProperties cimProperties;


    private final HashMap<String, CIMRequestHandler> webHandlerMap = new HashMap<>();


    @Bean(destroyMethod = "destroy")
    public CIMNioSocketServer getNioSocketServer() {
        if (StringUtils.isEmpty(cimProperties.getHost()))
            throw new RuntimeException("cim.host can not be empty,please check your configuration!");
        if (cimProperties.getPort() == CIMConstant.DEFAULT_PORT)
            log.warn("cim used default port:" + CIMConstant.DEFAULT_PORT);


        return new CIMNioSocketServer.Builder()
                .wsConfig(cimProperties.getHost(), cimProperties.getPort())
                .setOuterRequestHandler(this)
                .build();

    }

    @Override
    public void process(CIMSession session, CIMMsg body) {
        CIMRequestHandler handler = webHandlerMap.get(body.getType());
        if (handler == null) {
            return;
        }
        handler.process(session, body);
    }

    /**
     * springboot启动完成之后再启动cim服务的，避免服务正在重启时，客户端会立即开始连接导致意外异常发生.
     */
    @Override
    public void onApplicationEvent(ApplicationStartedEvent applicationStartedEvent) {

        try {
            // 从配置文件读取handler 并加载指定handler。
            loadConfigHandler();

            webHandlerMap.put(SocketHandlerEnum.CLIENT_AUTHORIZATION.getCode(), applicationContext.getBean(AuthorizationHandler.class));
            webHandlerMap.put(SocketHandlerEnum.CLIENT_CLOSED.getCode(), applicationContext.getBean(SessionClosedHandler.class));

            applicationContext.getBean(CIMNioSocketServer.class).bind();
        } catch (Exception e) {
            log.error("[cim] 绑定handler时出现异常，终止", e);
        }
    }

    /**
     * 动态加载配置中的 handler
     *
     * @author chentl
     * @version v1.0.0
     * @since 3:02 下午 2022/8/2
     **/
    private void loadConfigHandler() {
        Map<String, String> hanlderMap = cimProperties.getHandlerMap();
        if (MapUtils.isNotEmpty(hanlderMap)) {
            hanlderMap.forEach((theme, handler) -> {
                try {
                    Class<CIMRequestHandler> handlerClass = (Class<CIMRequestHandler>) Class.forName(handler);
                    webHandlerMap.put(theme, applicationContext.getBean(handlerClass));
                } catch (ClassNotFoundException e) {
                    log.error("[cim] 动态加载handler时发生异常，终止netty服务启动");
                }
            });
        }
    }
}